// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

<template>
  <a-row class="capacity-dashboard" :gutter="[12,12]">
    <a-col :span="24">
      <div class="capacity-dashboard-wrapper">
        <div class="capacity-dashboard-select">
          <a-select
            :placeholder="$t('label.select.a.zone')"
            v-model:value="zoneSelectedKey"
            @change="changeZone"
            showSearch
            optionFilterProp="label"
            :filterOption="(input, option) => {
              return  option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
            }" >
            <a-select-option v-for="(zone, index) in zones" :key="index" :label="zone.name">
              <span>
                <resource-icon v-if="zone.icon && zone.icon.base64image" :image="zone.icon.base64image" size="2x" style="margin-right: 5px"/>
                <global-outlined v-else style="margin-right: 5px" />
                {{ zone.name }}
              </span>
            </a-select-option>
          </a-select>
        </div>
        <div class="capacity-dashboard-button">
          <a-button
            shape="round"
            @click="() => { updateData(zoneSelected); listAlerts(); listEvents(); }">
            <reload-outlined/>
            {{ $t('label.fetch.latest') }}
          </a-button>
        </div>
      </div>
    </a-col>
    <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }">
      <chart-card :loading="loading" class="dashboard-card">
        <template #title>
          <div class="center">
            <router-link :to="{ path: '/infrasummary' }" v-if="!zoneSelected.id">
              <h3>
                <bank-outlined />
                {{ $t('label.infrastructure') }}
              </h3>
            </router-link>
            <router-link :to="{ path: '/zone/' + zoneSelected.id }" v-else>
              <h3>
                <global-outlined />
                {{ $t('label.zone') }}
              </h3>
            </router-link>
          </div>
        </template>
        <a-divider style="margin: 0px 0px; border-width: 0px"/>
        <a-row :gutter="[12, 12]">
          <a-col :span="12">
            <router-link :to="{ path: '/pod', query: { zoneid: zoneSelected.id } }">
              <a-statistic
                :title="$t('label.pods')"
                :value="data.pods"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <appstore-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/cluster', query: { zoneid: zoneSelected.id } }">
              <a-statistic
                :title="$t('label.clusters')"
                :value="data.clusters"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <cluster-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/host', query: { zoneid: zoneSelected.id } }">
              <a-statistic
                :title="$t('label.hosts')"
                :value="data.totalHosts"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <database-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/host', query: { zoneid: zoneSelected.id, state: 'alert' } }">
              <a-statistic
                :title="$t('label.host.alerts')"
                :value="data.alertHosts"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <database-outlined/>
                  <a-badge v-if="data.alertHosts > 0" count="!" style="margin-left: -5px" />
                  <a-badge v-else count="✓" style="margin-left: -5px" :number-style="{ backgroundColor: '#52c41a' }" />
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/storagepool', query: { zoneid: zoneSelected.id } }">
              <a-statistic
                :title="$t('label.primary.storage')"
                :value="data.pools"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <hdd-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/systemvm', query: { zoneid: zoneSelected.id } }">
              <a-statistic
                :title="$t('label.system.vms')"
                :value="data.systemvms"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <thunderbolt-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/router', query: { zoneid: zoneSelected.id } }">
              <a-statistic
                :title="$t('label.virtual.routers')"
                :value="data.routers"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <fork-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
          <a-col :span="12">
            <router-link :to="{ path: '/vm', query: { zoneid: zoneSelected.id, projectid: '-1' } }">
              <a-statistic
                :title="$t('label.instances')"
                :value="data.instances"
                :value-style="{ color: $config.theme['@primary-color'] }">
                <template #prefix>
                  <cloud-server-outlined/>&nbsp;
                </template>
              </a-statistic>
            </router-link>
          </a-col>
        </a-row>
      </chart-card>
    </a-col>
    <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }">
      <chart-card :loading="loading" class="dashboard-card">
        <template #title>
          <div class="center">
            <h3><cloud-outlined /> {{ $t('label.compute') }}</h3>
          </div>
        </template>
        <div>
          <div v-for="ctype in ['MEMORY', 'CPU', 'CPU_CORE', 'GPU']" :key="ctype" >
            <div v-if="statsMap[ctype]">
              <div>
                <strong>{{ $t(ts[ctype]) }}</strong>
              </div>
              <a-progress
              status="active"
              :percent="statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal) : 0"
              :format="p => statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal).toFixed(2) + '%' : '0%'"
              stroke-color="#52c41a"
              size="small"
              style="width:95%; float: left"
              />
              <br/>
              <div style="text-align: center">
                {{ displayData(ctype, statsMap[ctype]?.capacityused) }} {{ $t('label.allocated') }} | {{ displayData(ctype, statsMap[ctype]?.capacitytotal) }} {{ $t('label.total') }}
              </div>
            </div>
          </div>
        </div>
      </chart-card>
    </a-col>
    <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }">
      <chart-card :loading="loading" class="dashboard-card">
        <template #title>
          <div class="center">
            <h3><hdd-outlined /> {{ $t('label.storage') }}</h3>
          </div>
        </template>
        <div>
          <div v-for="ctype in ['STORAGE', 'STORAGE_ALLOCATED', 'LOCAL_STORAGE', 'SECONDARY_STORAGE']" :key="ctype" >
            <div v-if="statsMap[ctype]">
              <div>
                <strong>{{ $t(ts[ctype]) }}</strong>
              </div>
              <a-progress
              status="active"
              :percent="statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal) : 0"
              :format="p => statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal).toFixed(2) + '%' : '0%'"
              stroke-color="#52c41a"
              size="small"
              style="width:95%; float: left"
              />
              <br/>
              <div style="text-align: center">
                {{ displayData(ctype, statsMap[ctype]?.capacityused) }} <span v-if="ctype !== 'STORAGE'">{{ $t('label.allocated') }}</span><span v-else>{{ $t('label.used') }}</span> | {{ displayData(ctype, statsMap[ctype]?.capacitytotal) }} {{ $t('label.total') }}
              </div>
            </div>
          </div>
        </div>
      </chart-card>
    </a-col>
    <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }">
      <chart-card :loading="loading" class="dashboard-card">
        <template #title>
          <div class="center">
            <h3><apartment-outlined /> {{ $t('label.network') }}</h3>
          </div>
        </template>
        <div>
          <div v-for="ctype in ['VLAN', 'VIRTUAL_NETWORK_PUBLIC_IP', 'VIRTUAL_NETWORK_IPV6_SUBNET', 'DIRECT_ATTACHED_PUBLIC_IP', 'PRIVATE_IP']" :key="ctype" >
            <div v-if="statsMap[ctype]">
              <div>
                <strong>{{ $t(ts[ctype]) }}</strong>
              </div>
              <a-progress
              status="active"
              :percent="statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal) : 0"
              :format="p => statsMap[ctype]?.capacitytotal > 0 ? parseFloat(100.0 * statsMap[ctype]?.capacityused / statsMap[ctype]?.capacitytotal).toFixed(2) + '%' : '0%'"
              stroke-color="#52c41a"
              size="small"
              style="width:95%; float: left"
              />
              <br/>
              <div style="text-align: center">
                {{ displayData(ctype, statsMap[ctype]?.capacityused) }} {{ $t('label.allocated') }} | {{ displayData(ctype, statsMap[ctype]?.capacitytotal) }} {{ $t('label.total') }}
              </div>
            </div>
          </div>
        </div>
      </chart-card>
    </a-col>
    <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }">
      <router-link :to="{ path: '/alert' }">
      <a-card :loading="loading" :bordered="false" class="dashboard-card dashboard-event">
        <div class="center" style="margin-top: -8px">
          <h3>
            <flag-outlined />
            {{ $t('label.alerts') }}
          </h3>
        </div>
        <a-divider style="margin: 6px 0px; border-width: 0px"/>
        <a-timeline>
          <a-timeline-item
            v-for="alert in alerts"
            :key="alert.id"
            color="red">
            <span :style="{ color: '#999' }"><small>{{ $toLocaleDate(alert.sent) }}</small></span>&nbsp;
            <span :style="{ color: '#666' }"><small><router-link :to="{ path: '/alert/' + alert.id }">{{ alert.name }}</router-link></small></span><br/>
            <span :style="{ color: '#aaa' }">{{ alert.description }}</span>
          </a-timeline-item>
        </a-timeline>
        <router-link :to="{ path: '/alert' }">
          <a-button>
            {{ $t('label.view') }} {{ $t('label.alerts') }}
          </a-button>
        </router-link>
      </a-card>
      </router-link>
    </a-col>
    <a-col :xs="{ span: 24 }" :lg="{ span: 12 }" :xl="{ span: 8 }" :xxl="{ span: 8 }">
      <router-link :to="{ path: '/event' }">
      <a-card :loading="loading" :bordered="false" class="dashboard-card dashboard-event">
        <div class="center" style="margin-top: -8px">
          <h3>
            <schedule-outlined />
            {{ $t('label.events') }}
          </h3>
        </div>
        <a-divider style="margin: 6px 0px; border-width: 0px"/>
        <a-timeline>
          <a-timeline-item
            v-for="event in events"
            :key="event.id"
            :color="getEventColour(event)">
            <span :style="{ color: '#999' }"><small>{{ $toLocaleDate(event.created) }}</small></span>&nbsp;
            <span :style="{ color: '#666' }"><small><router-link :to="{ path: '/event/' + event.id }">{{ event.type }}</router-link></small></span><br/>
            <span>
              <resource-label :resourceType="event.resourcetype" :resourceId="event.resourceid" :resourceName="event.resourcename" />
            </span>
            <span :style="{ color: '#aaa' }">({{ event.username }}) {{ event.description }}</span>
          </a-timeline-item>
        </a-timeline>
        <router-link :to="{ path: '/event' }">
          <a-button>
            {{ $t('label.view') }} {{ $t('label.events') }}
          </a-button>
        </router-link>
      </a-card>
      </router-link>
    </a-col>
  </a-row>
</template>

<script>
import { api } from '@/api'

import ChartCard from '@/components/widgets/ChartCard'
import ResourceIcon from '@/components/view/ResourceIcon'
import ResourceLabel from '@/components/widgets/ResourceLabel'
import Status from '@/components/widgets/Status'

export default {
  name: 'CapacityDashboard',
  components: {
    ChartCard,
    ResourceIcon,
    ResourceLabel,
    Status
  },
  data () {
    return {
      loading: true,
      tabKey: 'alerts',
      alerts: [],
      events: [],
      zones: [],
      zoneSelected: {},
      statsMap: {},
      data: {
        pods: 0,
        clusters: 0,
        totalHosts: 0,
        alertHosts: 0,
        pools: 0,
        instances: 0,
        systemvms: 0,
        routers: 0
      },
      ts: {
        CPU: 'label.cpu',
        CPU_CORE: 'label.cpunumber',
        DIRECT_ATTACHED_PUBLIC_IP: 'label.direct.ips',
        GPU: 'label.gpu',
        LOCAL_STORAGE: 'label.local.storage',
        MEMORY: 'label.memory',
        PRIVATE_IP: 'label.management.ips',
        SECONDARY_STORAGE: 'label.secondary.storage',
        STORAGE: 'label.primary.storage.used',
        STORAGE_ALLOCATED: 'label.primary.storage.allocated',
        VIRTUAL_NETWORK_PUBLIC_IP: 'label.public.ips',
        VLAN: 'label.vlan',
        VIRTUAL_NETWORK_IPV6_SUBNET: 'label.ipv6.subnets'
      }
    }
  },
  computed: {
    zoneSelectedKey () {
      if (this.zones.length === 0) {
        return this.zoneSelected.name
      }
      const zoneIndex = this.zones.findIndex(zone => zone.id === this.zoneSelected.id)
      return zoneIndex
    }
  },
  created () {
    this.fetchData()
  },
  watch: {
    '$route' (to, from) {
      if (to.name === 'dashboard') {
        this.fetchData()
      }
    }
  },
  methods: {
    getStatus (value) {
      if (value > 85) {
        return 'exception'
      }
      if (value > 75) {
        return 'active'
      }
      return 'normal'
    },
    displayData (dataType, value) {
      if (!value) {
        value = 0
      }
      switch (dataType) {
        case 'CPU':
          value = parseFloat(value / 1000.0, 10).toFixed(2) + ' GHz'
          break
        case 'MEMORY':
        case 'STORAGE':
        case 'STORAGE_ALLOCATED':
        case 'SECONDARY_STORAGE':
        case 'LOCAL_STORAGE':
          value = parseFloat(value / (1024 * 1024 * 1024.0), 10).toFixed(2)
          if (value >= 1024.0) {
            value = parseFloat(value / 1024.0).toFixed(2) + ' TiB'
          } else {
            value = value + ' GiB'
          }
          break
      }
      return value
    },
    fetchData () {
      this.listZones()
      this.listAlerts()
      this.listEvents()
    },
    listCapacity (zone, latest = false, additive = false) {
      this.loading = true
      api('listCapacity', { zoneid: zone.id, fetchlatest: latest }).then(json => {
        this.loading = false
        let stats = []
        if (json && json.listcapacityresponse && json.listcapacityresponse.capacity) {
          stats = json.listcapacityresponse.capacity
        }
        for (const stat of stats) {
          if (additive) {
            for (const [key, value] of Object.entries(stat)) {
              if (stat.name in this.statsMap) {
                if (key in this.statsMap[stat.name]) {
                  this.statsMap[stat.name][key] += value
                } else {
                  this.statsMap[stat.name][key] = value
                }
              } else {
                this.statsMap[stat.name] = { key: value }
              }
            }
          } else {
            this.statsMap[stat.name] = stat
          }
        }
      })
    },
    updateData (zone) {
      if (!zone.id) {
        this.statsMap = {}
        for (const zone of this.zones.slice(1)) {
          this.listCapacity(zone, true, true)
        }
      } else {
        this.statsMap = {}
        this.listCapacity(this.zoneSelected, true)
      }

      this.data = {
        pods: 0,
        clusters: 0,
        totalHosts: 0,
        alertHosts: 0,
        pools: 0,
        instances: 0,
        systemvms: 0,
        routers: 0
      }
      this.loading = true
      api('listPods', { zoneid: zone.id }).then(json => {
        this.loading = false
        this.data.pods = json?.listpodsresponse?.count
        if (!this.data.pods) {
          this.data.pods = 0
        }
      })
      api('listClusters', { zoneid: zone.id }).then(json => {
        this.loading = false
        this.data.clusters = json?.listclustersresponse?.count
        if (!this.data.clusters) {
          this.data.clusters = 0
        }
      })
      api('listHosts', { zoneid: zone.id, listall: true, details: 'min', type: 'routing', page: 1, pagesize: 1 }).then(json => {
        this.loading = false
        this.data.totalHosts = json?.listhostsresponse?.count
        if (!this.data.totalHosts) {
          this.data.totalHosts = 0
        }
      })
      api('listHosts', { zoneid: zone.id, listall: true, details: 'min', type: 'routing', state: 'alert', page: 1, pagesize: 1 }).then(json => {
        this.loading = false
        this.data.alertHosts = json?.listhostsresponse?.count
        if (!this.data.alertHosts) {
          this.data.alertHosts = 0
        }
      })
      api('listStoragePools', { zoneid: zone.id }).then(json => {
        this.loading = false
        this.data.pools = json?.liststoragepoolsresponse?.count
        if (!this.data.pools) {
          this.data.pools = 0
        }
      })
      api('listSystemVms', { zoneid: zone.id }).then(json => {
        this.loading = false
        this.data.systemvms = json?.listsystemvmsresponse?.count
        if (!this.data.systemvms) {
          this.data.systemvms = 0
        }
      })
      api('listRouters', { zoneid: zone.id, listall: true, projectid: '-1' }).then(json => {
        this.loading = false
        this.data.routers = json?.listroutersresponse?.count
        if (!this.data.routers) {
          this.data.routers = 0
        }
      })
      api('listVirtualMachines', { zoneid: zone.id, listall: true, projectid: '-1', details: 'min', page: 1, pagesize: 1 }).then(json => {
        this.loading = false
        this.data.instances = json?.listvirtualmachinesresponse?.count
        if (!this.data.instances) {
          this.data.instances = 0
        }
      })
    },
    listAlerts () {
      const params = {
        page: 1,
        pagesize: 8,
        listall: true
      }
      this.loading = true
      api('listAlerts', params).then(json => {
        this.alerts = []
        this.loading = false
        if (json && json.listalertsresponse && json.listalertsresponse.alert) {
          this.alerts = json.listalertsresponse.alert
        }
      })
    },
    listEvents () {
      const params = {
        page: 1,
        pagesize: 8,
        listall: true
      }
      this.loading = true
      api('listEvents', params).then(json => {
        this.events = []
        this.loading = false
        if (json && json.listeventsresponse && json.listeventsresponse.event) {
          this.events = json.listeventsresponse.event
        }
      })
    },
    getEventColour (event) {
      if (event.level === 'ERROR') {
        return 'red'
      }
      if (event.state === 'Completed') {
        return 'green'
      }
      return 'blue'
    },
    listZones () {
      api('listZones', { showicon: true }).then(json => {
        if (json && json.listzonesresponse && json.listzonesresponse.zone) {
          this.zones = json.listzonesresponse.zone
          if (this.zones.length > 0) {
            this.zones.splice(0, 0, { name: this.$t('label.all.zone') })
            this.zoneSelected = this.zones[0]
            this.updateData(this.zones[0])
          }
        }
      })
    },
    changeZone (index) {
      this.zoneSelected = this.zones[index]
      this.updateData(this.zoneSelected)
    },
    filterZone (input, option) {
      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
    }
  }
}
</script>

<style lang="less" scoped>
.capacity-dashboard {
  &-wrapper {
    display: flex;
  }

  &-chart-card-inner {
     text-align: center;
     white-space: nowrap;
     overflow: hidden;
  }

  &-select {
    width: 100%; // for flexbox causes

    .ant-select {
      width: 100%; // to fill flex item width
    }
  }

  &-button-wrapper {
    margin-left: 12px;
  }

  &-button {
    width: auto;
    padding-left: 8px;
  }

  &-button-icon {
    font-size: 16px;
    padding: 2px;
  }

  &-title {
    padding-top: 12px;
    padding-left: 3px;
    white-space: normal;
  }
}

.dashboard-card {
  width: 100%;
  min-height: 370px;
}

.dashboard-event {
  width: 100%;
  overflow-x:hidden;
  overflow-y: auto;
  max-height: 370px;
}

.center {
  display: block;
  text-align: center;
}

</style>
